package han.chensing.latos.game;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.utils.Align;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import han.chensing.latos.AndroidV;
import han.chensing.latos.V;
import han.chensing.latos.common.level.LatosProject;
import han.chensing.latos.game.elements.character.Character;
import han.chensing.latos.game.elements.character.CharacterInstance;
import han.chensing.latos.game.elements.character.impl.TestCharacter2;
import han.chensing.latos.game.elements.notes.Line;
import han.chensing.latos.game.elements.stage.LatosStage;
import han.chensing.latos.game.elements.stage.NoteStage;
import han.chensing.latos.game.input.TouchContainer;
import han.chensing.latos.game.processor.ComboCounter;
import han.chensing.latos.game.processor.EventHandler;
import han.chensing.latos.game.processor.JudgeHandler;
import han.chensing.latos.game.processor.LevelTranslator;
import han.chensing.latos.game.util.MathUtil;
import han.chensing.latos.game.util.NoteUtil;
import han.chensing.latos.res.Res;

public class GameScreen implements Screen {

    NoteStage noteStage;
    LatosStage effectStage;
    TouchContainer touchContainer;
    EventHandler eventHandler;
    ComboCounter comboCounter;
    JudgeHandler judgeHandler;

    BitmapFont consolasFont50;
    BitmapFont consolasFont20;
    SpriteBatch fontBatch;
    CharacterInstance characterInstance;
    File tempMusicFile;
    LatosProject latosProject;

    boolean started=false;
    Color bgColor=Color.valueOf("#1f1e33");
    float currentMusicTime;
    long startMusicTime;
    Music music;

    long startDelay;
    boolean isAndroid=Gdx.app.getType()==Application.ApplicationType.Android;

    public GameScreen(){
        try {
            eventHandler =new EventHandler();
            Character testCharacter = new TestCharacter2();
            comboCounter = new ComboCounter(characterInstance= testCharacter.genInstance());
            noteStage = new NoteStage();
            effectStage = new LatosStage();
            touchContainer = new TouchContainer(V.setting.multiThreadInput);
            consolasFont50 = Res.getInstance().get("fontConsolas50", BitmapFont.class);
            consolasFont20 = Res.getInstance().get("fontConsolas20", BitmapFont.class);
            judgeHandler=new JudgeHandler();
            fontBatch = new SpriteBatch();
            Gdx.input.setInputProcessor(touchContainer);
            init();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    protected void init()
            throws IOException, NoSuchMethodException,
            InstantiationException, IllegalAccessException,
            InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
        FileHandle fileHandle=Gdx.files.internal("Out.lat");
        byte[] bytes = fileHandle.readBytes();
        Object[] translate = LevelTranslator.translateWholeLevel(bytes);
        if (translate==null)return;
        List<Line> lines = (List<Line>) translate[1];
        LatosProject latosProject=(LatosProject)translate[0];
        this.latosProject=latosProject;
        Random random=new Random();
        tempMusicFile=File.createTempFile("musicCache"+random.nextInt(),"."+ latosProject.getMusicFormat());
        FileOutputStream fileOutputStream=new FileOutputStream(tempMusicFile);
        fileOutputStream.write((byte[])translate[2]);
        fileOutputStream.close();
        music=Gdx.audio.newMusic(Gdx.files.absolute(tempMusicFile.getAbsolutePath()));
        tempMusicFile.deleteOnExit();
        for (Line line : lines){
            line.getNoteSpeed().getSpeed().x=1600;
            line.setX(V.WIDTH/2f);
            line.setY(2000);
            noteStage.addElement(line);
        }
        eventHandler.resetTimeLine(
                latosProject.getLevelData().getTimeLine());
        comboCounter.setAllNotes(NoteUtil.getFullCombo(latosProject));
        music.play();
        music.pause();
        this.startDelay=System.currentTimeMillis()+3000;
        startMusicTime=System.nanoTime();
    }

    @Override
    public void show() {

    }

    @Override
    public void render(float delta) {
        V.globalViewport.apply(true);
        Gdx.gl.glClearColor(bgColor.r,bgColor.g,bgColor.b, 1f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        effectStage.combineCamera(V.globalCamera);
        noteStage.combineCamera(V.globalCamera);

        currentMusicTime = V.setting.useAbsoluteTime?(music.getPosition()):
                (started?(System.nanoTime()-startMusicTime)/1E9F:0+(isAndroid?.08f:0f));
        judgeHandler.judgeLines(
                currentMusicTime,
                noteStage, effectStage, touchContainer,comboCounter);

        eventHandler.select(currentMusicTime);
        eventHandler.handle(noteStage,currentMusicTime);

        V.shapeRenderer.setProjectionMatrix(V.globalCamera.combined);
        V.shapeRenderer.setColor(Color.WHITE);
        V.shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);

        drawHealthBar(
                characterInstance.getMaxHealth(),
                characterInstance.getBufferHealth(),
                characterInstance.getBufferColor());
        drawHealthBar(
                characterInstance.getMaxHealth(),
                characterInstance.getShownHealth(),
                characterInstance.getHealthColor());
        drawHealthBar(
                characterInstance.getMaxHealth(),
                characterInstance.getShownHealth(),
                characterInstance.getHurtColor());

        drawProgressBar(characterInstance.getHealthColor());

        noteStage.act(delta, currentMusicTime);
        effectStage.act(delta, currentMusicTime);

        noteStage.draw();
        effectStage.draw();

        fontBatch.setProjectionMatrix(V.globalCamera.combined);
        fontBatch.begin();
        if (comboCounter.getCombo()>=3) {
            consolasFont50.draw(fontBatch,
                    comboCounter.getComboString(),
                    V.WIDTH / 2f, V.HEIGHT - 18, 0, Align.center, false);
            consolasFont20.draw(fontBatch,
                    "COMBO",
                    V.WIDTH / 2f, V.HEIGHT - 55, 0, Align.center, false);
        }
        consolasFont50.draw(fontBatch,comboCounter.getScore(),
                V.WIDTH-18,V.HEIGHT-18,0,Align.right,false);

        if (isAndroid) {
            consolasFont20.draw(fontBatch,
                    String.format(Locale.CHINA,
                            "Now using cirno-sound interface(experimental) (SR:%d|FPB:%d|U:%d)",
                            AndroidV.sampleRate,AndroidV.framesPerBuffer,AndroidV.getAudioBufferUsage()),
                    10, 60, V.WIDTH - 20, Align.left, false);
            consolasFont20.draw(fontBatch, AndroidV.supportLowLatency?
                    "This device supports Low-Latency Audio function (*^v^*)"
                            :"This device DOES NOT support Low-Latency Audio function (T^T)",
                    10, 30, V.WIDTH - 20, Align.left, false);
        }

        fontBatch.end();
        V.shapeRenderer.end();

        V.shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
        Line line = (Line) noteStage.getElements().get(0);
        for (TouchContainer.Touch touch : touchContainer.getTouches()) {
            if (touch.isTouched()){
                int pnFix = MathUtil.getPointSideFix(line.getX(), line.getY(),
                        line.getRotation(),touch.getX(), touch.getY());
                V.shapeRenderer.setColor(pnFix==1?Color.GREEN:Color.RED);
                V.shapeRenderer.circle(touch.getX(), touch.getY(),15);
                V.shapeRenderer.setColor(Color.WHITE);
            }
        }
        V.shapeRenderer.end();

        Gdx.gl.glEnable(GL20.GL_BLEND);
        Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
        V.shapeRenderer.run();

        if (Gdx.input.isKeyJustPressed(Input.Keys.S)){
            characterInstance.invokeMessage("onGood");
        }
        if (Gdx.input.isKeyJustPressed(Input.Keys.A)){
            characterInstance.invokeMessage("onBad");
        }

        if (this.startDelay>=System.currentTimeMillis())return;
        if (!started){
            music.play();
            started=true;
            startMusicTime=System.nanoTime();
        }

        characterInstance.invokeTick(delta);
    }

    private void drawProgressBar(Color color){
        float perCent=(currentMusicTime/ (latosProject.getMusicLength()/1000f));
        V.shapeRenderer.rect(0,V.HEIGHT-5,
                perCent*V.WIDTH, 5,color,color,color,color);
    }

    private void drawHealthBar(float max,float current,Color color){
        float health = current / max
                * V.HEIGHT;
        V.shapeRenderer.rect(0,V.HEIGHT/2f-health/2f,5 ,health,color,color,color,color);
        V.shapeRenderer.rect(V.WIDTH-5,V.HEIGHT/2f-health/2f,5 ,health,color,color,color,color);
    }

    @Override
    public void resize(int width, int height) {
        V.globalViewport.update(width, height,true);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {
        noteStage.dispose();
        effectStage.dispose();
        if (tempMusicFile!=null) tempMusicFile.deleteOnExit();
    }
}
